#include <gtest/gtest.h>
#include <thread>
#include <vector>
#include <fcntl.h>
extern "C" {
#include "gr_api.h"
#include "gr_errno.h"
}

#define TEST_LOG_DIR "./test_log"
#define TEST_DIR "appenddir"
#define TEST_FILE1 "file1"
#define TEST_FILE2 "file2"
#define ONE_GB 1024 * 1024 * 1024
#define SERVER_ADDR "127.0.0.1:19225"

int errorcode = 0;
const char *errormsg = NULL;
gr_instance_handle g_inst_handle1 = NULL;
gr_instance_handle g_inst_handle2 = NULL;
gr_vfs_handle g_vfs_handle1;
gr_vfs_handle g_vfs_handle2;
int handle1 = 0, handle2 = 0;

gr_file_handle file_handle1;
gr_file_handle file_handle2;

gr_param_t g_gr_param;

class AppendGRApiTest : public ::testing::Test {
protected:
    void SetUp() override {
        strcpy(g_gr_param.log_home, "./testlog");
        g_gr_param.log_level = 255;
        g_gr_param.log_backup_file_count = 100;
        g_gr_param.log_max_file_size = ONE_GB;
        int result = gr_init(g_gr_param);
        ASSERT_EQ(result, GR_SUCCESS) << "Failed to initialize logger";

        EXPECT_EQ(gr_create_inst(SERVER_ADDR, &g_inst_handle1), GR_SUCCESS);
        EXPECT_EQ(gr_create_inst(SERVER_ADDR, &g_inst_handle2), GR_SUCCESS);
        EXPECT_EQ(gr_vfs_create(g_inst_handle1, TEST_DIR, 0), GR_SUCCESS);
        EXPECT_EQ(gr_vfs_mount(g_inst_handle1, TEST_DIR, &g_vfs_handle1), GR_SUCCESS);
        EXPECT_EQ(gr_vfs_mount(g_inst_handle2, TEST_DIR, &g_vfs_handle2), GR_SUCCESS);
        EXPECT_EQ(gr_file_create(g_vfs_handle1, TEST_FILE1, NULL), GR_SUCCESS);
        EXPECT_EQ(gr_file_create(g_vfs_handle2, TEST_FILE2, NULL), GR_SUCCESS);
        EXPECT_EQ(gr_file_open(g_vfs_handle1, TEST_FILE1, O_RDWR | O_SYNC, &file_handle1), GR_SUCCESS);
        EXPECT_EQ(gr_file_open(g_vfs_handle2, TEST_FILE2, O_RDWR | O_SYNC, &file_handle2), GR_SUCCESS);
    }

    void TearDown() override {
        EXPECT_EQ(gr_file_close(g_vfs_handle1, &file_handle1, false), GR_SUCCESS); 
        EXPECT_EQ(gr_file_close(g_vfs_handle2, &file_handle2, false), GR_SUCCESS);
        EXPECT_EQ(gr_vfs_unmount(&g_vfs_handle1), GR_SUCCESS);
        EXPECT_EQ(gr_vfs_unmount(&g_vfs_handle2), GR_SUCCESS);
#ifndef ENABLE_WORM
        EXPECT_EQ(gr_vfs_delete(g_inst_handle1, TEST_DIR, 1), GR_SUCCESS);
#endif
    }
};

TEST_F(AppendGRApiTest, TestWrite) {
    const int data_size1 = 512 * 1024; // 512KB
    const int data_size2 = 256 * 1024; // 256KB
    char *data1 = new char[data_size1];
    char *data2 = new char[data_size2];
    memset(data1, 'A', data_size1);
    memset(data2, 'B', data_size2);

    char *read_buffer1 = new char[data_size1];
    char *read_buffer2 = new char[data_size2];

    std::vector<std::thread> threads;

    // 写数据
    EXPECT_EQ(gr_file_pwrite(g_vfs_handle1, &file_handle1, data1, data_size1, 0), data_size1);
    EXPECT_EQ(gr_file_pwrite(g_vfs_handle2, &file_handle2, data2, data_size2, 0), data_size2);
    // 读数据
    EXPECT_EQ(gr_file_pread(g_vfs_handle1, file_handle1, read_buffer1, data_size1, 0), data_size1);
    EXPECT_EQ(gr_file_pread(g_vfs_handle2, file_handle2, read_buffer2, data_size2, 0), data_size2);


    // 验证读取的数据是否与写入的数据一致
    EXPECT_EQ(memcmp(data1, read_buffer1, data_size1), 0);
    EXPECT_EQ(memcmp(data2, read_buffer2, data_size2), 0);

    // close file and change into lock mode
    EXPECT_EQ(gr_file_close(g_vfs_handle1, &file_handle1, true), GR_SUCCESS);
    EXPECT_EQ(gr_file_close(g_vfs_handle2, &file_handle2, true), GR_SUCCESS);

    EXPECT_EQ(gr_file_open(g_vfs_handle1, TEST_FILE1, O_RDONLY, &file_handle1), GR_SUCCESS);
    EXPECT_EQ(gr_file_open(g_vfs_handle2, TEST_FILE2, O_RDONLY, &file_handle2), GR_SUCCESS);

    // 读数据
    EXPECT_EQ(gr_file_pread(g_vfs_handle1, file_handle1, read_buffer1, data_size1, 0), data_size1);
    EXPECT_EQ(gr_file_pread(g_vfs_handle2, file_handle2, read_buffer2, data_size2, 0), data_size2);

    delete[] data1;
    delete[] data2;
    delete[] read_buffer1;
    delete[] read_buffer2;
}

int main(int argc, char **argv) {
    ::testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}